package com.wuuxiang.polestar.core.spring.surpass;

import java.util.ArrayList;
import java.util.List;
import java.util.regex.Pattern;

import org.apache.curator.framework.CuratorFramework;
import org.apache.curator.framework.CuratorFrameworkFactory;
import org.apache.curator.framework.api.GetChildrenBuilder;
import org.apache.curator.utils.ZKPaths;
import org.apache.zookeeper.data.Stat;
import org.springframework.core.env.MutablePropertySources;
import org.springframework.core.env.PropertySources;

import com.google.common.base.Preconditions;
import com.google.common.base.Throwables;
import com.wuuxiang.polestar.comm.constant.Constant;
import com.wuuxiang.polestar.core.ConfigGroup;
import com.wuuxiang.polestar.core.room.RoomName;
import com.wuuxiang.polestar.core.spring.ConfigGroupEnumerableResource;
import com.wuuxiang.polestar.core.spring.ConfigGroupResource;
import com.wuuxiang.polestar.core.zookeeper.surpass.ZookeeperSurPassConfigProfile;
import com.wuuxiang.utils.des.DESUtils;
import com.wuuxiang.utils.string.StrUtils;

public class PolestarSurPassGroupSourceFactory {
	
	private static List<String> encryptPropNamesList;
	/** 分库db正则表达式 */
	private static final String SHARING_DB_PATTERN = "^sharing_db_.*$";
	
	private static void fillDecKey(ZookeeperSurPassConfigProfile configProfile) {
		CuratorFramework client = CuratorFrameworkFactory.newClient(configProfile.getConnectStr(), configProfile.getRetryPolicy());
		client.start();
        // 获取加密key路径
        String decKeyPath = ZKPaths.makePath(Constant.ROOT_NODE, Constant.SECURITY_NODE);
        try {
            Stat stat = client.checkExists().forPath(decKeyPath);
            if (stat != null) {
                GetChildrenBuilder childrenBuilder = client.getChildren();
                encryptPropNamesList = childrenBuilder.forPath(decKeyPath);
            }
        } catch (Exception e) {
            throw Throwables.propagate(e);
        }
	}

	public static PropertySources create(ZookeeperSurPassConfigProfile configProfile, ConfigGroup... configGroups) {
		// 加载加密key
		fillDecKey(configProfile);
		if (null == encryptPropNamesList) {
			encryptPropNamesList = new ArrayList<String>();
		}
		Preconditions.checkNotNull(configGroups);
		final MutablePropertySources sources = new MutablePropertySources();
		Pattern pattern = Pattern.compile(SHARING_DB_PATTERN);
		for (ConfigGroup configGroup : configGroups) {
			if (configGroup != null) {
				// 进行解密
				for (String key : configGroup.keySet()) {
					if (encryptPropNamesList.contains(key) || pattern.matcher(key).find()) {
						configGroup.put(key, DESUtils.getDecryptString(configGroup.get(key)));
					}
					if ("group.name".equals(key)) {
						// 如果docker容器传入机房配置环境变量则重新设置机房名称
						if (StrUtils.isNotBlank(RoomName.getRoom())) {
							// 覆盖从配置中心读取的机房名称
							configGroup.put("group.name", RoomName.getRoom());
						}
					}
				}
				sources.addLast(new ConfigGroupResource(configGroup));
			}
		}
		return sources;
	}

	/**
	 * ********************************************************<br>
	 * 方法说明： 添加springboot支持 <br>
	 * 参数： @param sources 参数： @param configGroups <br>
	 * 返回值： void <br>
	 * 创建人：夏鸿鹏 <br>
	 * 创建时间：2017年11月21日 下午2:15:57 <br>
	 * 修改备注： <br>
	 *********************************************************
	 * 
	 */
	public static void create(ZookeeperSurPassConfigProfile configProfile, MutablePropertySources sources, ConfigGroup... configGroups) {
		// 加载加密key
		fillDecKey(configProfile);
		if (null == encryptPropNamesList) {
			encryptPropNamesList = new ArrayList<String>();
		}
		Preconditions.checkNotNull(configGroups);
		Pattern pattern = Pattern.compile(SHARING_DB_PATTERN);
		for (ConfigGroup configGroup : configGroups) {
			if (configGroup != null) {
				// 进行解密
				for (String key : configGroup.keySet()) {
					if (encryptPropNamesList.contains(key) || pattern.matcher(key).find()) {
						configGroup.put(key, DESUtils.getDecryptString(configGroup.get(key)));
					}
					if ("group.name".equals(key)) {
						// 如果docker容器传入机房配置环境变量则重新设置机房名称
						if (StrUtils.isNotBlank(RoomName.getRoom())) {
							// 覆盖从配置中心读取的机房名称
							configGroup.put("group.name", RoomName.getRoom());
						}
					}
				}
				sources.addLast(new ConfigGroupEnumerableResource(configGroup));
			}
		}
	}

}
